package com.itcodai.service.impl;

import com.itcodai.controller.course12.MyEvent;
import com.itcodai.dao.user.UserMapper;
import com.itcodai.entity.User;
import com.itcodai.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.SQLException;
import java.util.List;

/**
 * @author c-fanqj
 * @date 2023/3/25
 * @apiNote
 */
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private ApplicationContext applicationContext;

    @Override
    public User getUser(Long id) {
        return userMapper.getUser(id);
    }

    @Override
    public List<User> getAll() {
        return userMapper.getAll();
    }

    @Override
    public User getUserByName(String name) {
        return userMapper.getUserByName(name);
    }

    @Override
    public User getUser(Long id, String name) {
        return userMapper.getUserByIdAndName(id, name);
    }

    @Override
    @Transactional
    public void insertUser(User user) {
        // 插入用户信息
        userMapper.insertUser(user);
        // 手动抛出异常
        throw new RuntimeException("手动抛出运行时异常");
    }

    /**
     * 事务问题一：异常没有被捕获到
     * 默认是遇到运行时异常RuntimeException和程序错误Error，才会回滚
     * @Transactional(rollbackFor = Exception.class)
     * @param user
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertUser2(User user) throws Exception {
        // 插入用户信息
        userMapper.insertUser(user);
        // 手动抛出异常
        throw new SQLException("数据库异常");
    }

    /**
     * 事务问题二：异常被吃掉 try-catch
     * 直接往上抛，给上一层来处理即可，千万不要在事务中把异常自己 ”吃“ 掉
     * @param user
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertUser3(User user) {
        try {
            // 插入用户信息
            userMapper.insertUser(user);
            // 手动抛出异常
            throw new SQLException("数据库异常");
        } catch (Exception e) {
            // 异常处理逻辑
            e.printStackTrace();
        }
    }

    /**
     * 事务问题三：事务的范围 并发问题
     * 事务的范围比锁的范围大 可重复读
     * 避免方法：事务去掉； 保证锁的范围比事务的范围大【推荐】
     * @param user
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized void insertUser4(User user) {
        // 插入用户信息
        userMapper.insertUser(user);
    }

    /**
     * 监听器：发布事件 触发逻辑
     * @return
     */
    @Override
    public User getUser2() {
        User user = new User(5L, "jiejie", "1234567890");
        // 发布事件
        MyEvent event = new MyEvent(this, user);
        applicationContext.publishEvent(event);
        return user;
    }

    /**
     * 获取用户信息
     * @return
     */
    @Override
    public User getUser() {
        // 实际中会根据具体的业务场景，从数据库中查询对应的信息
        return new User(1L, "fanlaoda", "123456");
    }

}
